/**
 * defineProperty(obj, prop, descriptor)直接在一个对象上定义一个新属性，或者修改一个已存在的属性，并返回这个对象
 * 参数obj:需要定义属性的对象
 * 参数prop:需要被定义或被修改的属性名
 * 参数descriptor:需被定义或修改的属性的描述符
 **/
var o = {};//创建一个新对象
//对象o拥有了a属性,值为37
/**
 * 添加属性
 * 对象属性类型：数据属性和访问器属性
 * 数据属性：configurable/enumerable/writable/value
 * 访问器属性:get/set
 */
Object.defineProperty(o, 'a', {
    value       : 37,
    writable    : true,//该属性为true时才能被赋值运算符改变 默认为false
    enumerable  : true,//可以被枚举(for in),默认为false
    configurable: true//可以被改变,也可以被删除,默认为false
})
var bValue;
Object.defineProperty(o, 'b', {
    get         : function () {
        return bValue;
    },
    set         : function (newValue) {
        return bValue = newValue;
    },
    enumerable  : true,
    configurable: true
});
o.b = 38;//对象o拥有了b属性，值为38
//数据描述符和存储描述符不能混合使用
/* Object.defineProperty(o,'conflict',{
 value:10,
 get: function () {
 return 10;
 }
 })*/


/**
 * 修改属性
 * 描述：该方法允许精确添加或修改对象的属性。一般情况下，我们为对象添加属性是通过赋值来创建并显示在属性枚举中（for...in 或 Object.keys 方法），
 * 但这种方式添加的属性值可以被改变，也可以被删除。而使用 Object.defineProperty() 则允许改变这些额外细节的默认设置。
 **/
//writable属性特性:当writable属性设置为false时，表示non-writable 即属性不能被修改,也不会报异常
var user = {};
Object.defineProperty(user, 'name', {
    value   : '骆泽熙',
    writable: false
});
console.log(user.name);
user.name = '骆柏燃';
console.log(user.name);

//enumerable属性特性： enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。
var enumerableObj = {a: 1, b: 2};
Object.defineProperty(enumerableObj, 'd', {
    value     : 3,
    enumerable: false
})
for (var o in enumerableObj) {
    console.log(enumerableObj[o]);  //false时1,2 true时:1,2,3
}
;


//configurable属性特性:表示对象的属性是否可以被删除，以及除 writable 特性外的其他特性是否可以被修改
var configurObj = {};
Object.defineProperty(configurObj, 'a', {
    get         : function () {
        return 1;
    },
    configurable: false
})
console.log(configurObj.a);